// SocketUtil.cpp: implementation of the SocketUtil class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "SocketUtil.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

BOOL SafeSend(SOCKET sock, const char* pBuf, int nLen)
{
	int nRet = 0;
	int nSended = 0;
	while (nSended < nLen)
	{
		nRet = send(sock, pBuf + nSended, nLen - nSended, 0);
		if (nRet <= 0)
		{
			break;
		}
		nSended += nRet;
	}
	if (nSended < nLen)
	{
		return FALSE;
	}
	return TRUE;
}

BOOL SafeRecv(SOCKET sock, char*pBuf, int nLen)
{
	int nRet = 0;
	int nRecved = 0;
	while (nRecved < nLen)
	{
		nRet = recv(sock, pBuf + nRecved, nLen - nRecved, 0);
		if (nRet <= 0)
		{
			break;
		}
		nRecved += nRet;
	}
	if (nRecved < nLen)
	{
		return FALSE;
	}
	return TRUE;
}

BOOL ConnectHasTimeout(SOCKET sock, struct sockaddr_in *pAddr, int nTimeOut)
{
	BOOL bResult = FALSE;
	do 
	{
		unsigned long ulVal = 1;
		if (0 != ioctlsocket(sock, FIONBIO, &ulVal))
		{
			break;
		}

		connect(sock, (struct sockaddr*)pAddr, sizeof(*pAddr));

		fd_set fsVal;
		FD_ZERO(&fsVal);
		FD_SET(sock, &fsVal);
		struct timeval tvTimeOut;
		tvTimeOut.tv_sec = nTimeOut/1000;
		tvTimeOut.tv_usec = (nTimeOut%1000)*1000;
		int nRet = select(0, 0, &fsVal, 0, &tvTimeOut);
		if (0 == nRet || SOCKET_ERROR == nRet)
		{
			break;
		}

		ulVal = 0;
		if (0 != ioctlsocket(sock, FIONBIO, &ulVal))
		{
			break;
		}

		bResult = TRUE;
	} while(0);

	return bResult;
}

BOOL WaitForSockCanRead(SOCKET sock, int nTimeOut /* = 1000 */)
{
	fd_set fsVal;
	FD_ZERO(&fsVal);
	FD_SET(sock, &fsVal);
	struct timeval tvTimeOut;
	tvTimeOut.tv_sec = nTimeOut/1000;
	tvTimeOut.tv_usec = (nTimeOut%1000)*1000;
	int nRet = select(0, &fsVal, 0, 0, &tvTimeOut);
	if (nRet > 0 && FD_ISSET(sock, &fsVal))
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

//wait until socket can be write
BOOL WaitForSockCanWrite(SOCKET sock, int timeout)
{
	fd_set fsVal;
	struct timeval tvTimeOut;
	int ret;

	FD_ZERO(&fsVal);
	FD_SET(sock, &fsVal);
	tvTimeOut.tv_sec = timeout/1000;
	tvTimeOut.tv_usec = (timeout%1000)*1000;
	ret = select(0, 0, &fsVal, 0, &tvTimeOut);
	if (ret > 0 && FD_ISSET(sock, &fsVal))
	{
		return TRUE;
	}

	return FALSE;
}

int sock_setReadTimeout(SOCKET sock, int timeout)
{
    return sock_setTimeout(sock, SO_RCVTIMEO, timeout);
}

int sock_setWriteTimeout(SOCKET sock, int timeout)
{
    return sock_setTimeout(sock, SO_SNDTIMEO, timeout);
}

int sock_setTimeout(SOCKET sock, int op, int timeout)
{
#ifdef WIN32
    int time;
    time = timeout;
#else
    struct timeval time;
    time.tv_sec = timeout/1000;
    time.tv_usec = (timeout%1000)*1000;
#endif
    return setsockopt(sock, SOL_SOCKET, op, (const char*)&time, sizeof(time));
}